package com.hehe.chat;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liuhao
 * @date 2019/6/24 17:44
 */
@ServerEndpoint(value = "/chat/{room}")
public class Chat {
    private static final String GUEST_PREFIX = "游客";
    /**
     * 一个提供原子操作的Integer的类。在Java语言中，++i和i++操作并不是线程安全的，
     * 在使用的时候，不可避免的会用到synchronized关键字。 而AtomicInteger则通过一种线程安全的加减操作接口。
     */
    private static final AtomicInteger connectionIds = new AtomicInteger(1);
    private static ConcurrentHashMap<String, Set<Chat>> webSocketSet = new ConcurrentHashMap<String, Set<Chat>>();


    private String nickname;
    private Session session;

    private String room;

    public Chat() {}

    /**
     * 创建连接时间调用的方法
     *
     * @param session
     */
    @OnOpen
    public void start(@PathParam(value="room") String r, Session session, EndpointConfig config) {
        room=r;

        HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        String tempName=(String) httpSession.getAttribute("userNameSession");
//System.out.println(tempName);
        if(tempName!=null){
            nickname=tempName;
        }
        else{
            nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
            httpSession.setAttribute("userNameSession", nickname);
        }
        this.session = session;
        if(webSocketSet.get(room)==null){
            Set<Chat> tempSet=new HashSet<>();
            tempSet.add(this);
            webSocketSet.put(room, tempSet);
        }else{
            webSocketSet.get(room).add(this);
        }
        String message = String.format("♡ %s %s",nickname,"进入直播间");

//上线通知
        broadcast(message);

    }

    /**
     * 链接关闭时调用方法
     */
    @OnClose
    public void end() {
        webSocketSet.get(room).remove(this);
        String message = String.format("♡ %s %s", nickname, "离开了直播间");
        broadcast(message);
    }
    /**
     * 传输信息过程中调用方法
     * @param message
     */
    @OnMessage
    public void incoming(String message) {
        String m = String.format("%s: %s", nickname, message);
        broadcast(m);

    }
    /**
     * 发生错误调用方法
     * @param t
     * @throws Throwable
     */
    @OnError
    public void onError(Throwable t) throws Throwable {
        System.out.println("错误: " + t.toString());
    }
    /**
     * 消息广播
     * 通过connections，对所有其他用户推送信息的方法
     * @param msg
     */
    private void broadcast(String msg) {
        for (Chat client : webSocketSet.get(room)) {
            try {
                synchronized (client) {
                    client.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                System.out.println("错误:向客户端发送消息失败");
                webSocketSet.remove(client);
                try {
                    client.session.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                String message = String.format("♡ %s %s", client.nickname,"离开了直播间");
                broadcast(message);
            }
        }
    }
}
